﻿using Microsoft.Xna.Framework;
using ShevaEngine.Core.Modules.Graphics;
using ShevaEngine.Core.Modules.Graphics.Cameras;
using ShevaEngine.Core.Modules.Scenes;
using Microsoft.Xna.Framework.Graphics;
using ShevaEngine.Core.Modules.Materials;
using System.Collections.Generic;

namespace Demo
{
    /// <summary>
    /// Heightmap terrain.
    /// </summary>
    public class HeightmapTerrain : SceneObject
    {
        /// <summary>Draw call.</summary>
        public UserPrimitivesDrawCall<VertexPositionNormalTexture> DrawCall;

        /// <summary>
        /// Constructor.
        /// </summary>
        public HeightmapTerrain()
        {
            this.World = Matrix.Identity;

            Texture2D heightmap = TextureManager.Instance.GetTexture("heightmap") as Texture2D;

            byte[] data = new byte[heightmap.Width * heightmap.Height * 4];

            heightmap.GetData<byte>(data);

            List<VertexPositionNormalTexture> vertices = new List<VertexPositionNormalTexture>();

            float dim = 32;

            for (int x = 0; x < heightmap.Width - 1; x++)
                for (int y = 0; y < heightmap.Height - 1; y++)
                {
                    Vector3 vertex1 = new Vector3(x * dim, (float)data[(int)(y * heightmap.Width + x) * 4], y * dim);
                    Vector3 vertex2 = new Vector3(x * dim, (float)data[(int)((y + 1) * heightmap.Width + x) * 4], (y + 1) * dim);
                    Vector3 vertex3 = new Vector3((x + 1) * dim, (float)data[(int)((y + 1) * heightmap.Width + (x + 1)) * 4], (y + 1) * dim);
                    Vector3 vertex4 = new Vector3((x + 1) * dim, (float)data[(int)(y * heightmap.Width + (x + 1)) * 4], y * dim);

                    Vector3 normal1 = Vector3.Cross(vertex2 - vertex1, vertex3 - vertex1);
                    Vector3 normal2 = Vector3.Cross(vertex2 - vertex4, vertex3 - vertex4);

                    vertices.Add(new VertexPositionNormalTexture(
                        vertex1, normal1, new Vector2(x * (1.0f / heightmap.Width), y * (1.0f / heightmap.Height))));
                    vertices.Add(new VertexPositionNormalTexture(
                        vertex2, normal1, new Vector2(x * (1.0f / heightmap.Width), (y + 1) * (1.0f / heightmap.Height))));
                    vertices.Add(new VertexPositionNormalTexture(
                        vertex3, normal1, new Vector2((x + 1) * (1.0f / heightmap.Width), (y + 1) * (1.0f / heightmap.Height))));

                    vertices.Add(new VertexPositionNormalTexture(
                        vertex1, normal1, new Vector2(x * (1.0f / heightmap.Width), y * (1.0f / heightmap.Height))));                    
                    vertices.Add(new VertexPositionNormalTexture(
                        vertex3, normal1, new Vector2((x + 1) * (1.0f / heightmap.Width), (y + 1) * (1.0f / heightmap.Height))));
                    vertices.Add(new VertexPositionNormalTexture(
                        vertex4, normal1, new Vector2((x + 1) * (1.0f / heightmap.Width), y * (1.0f / heightmap.Height))));
                }     

            Textures newTextures = new Textures();
            newTextures.Add("Diffuse", "decal");

            DrawCallKey newDrawCallKey = new DrawCallKey(
                MaterialManager.Instance.GetMaterialID("MaterialBaseVertexTextured"),
                TextureManager.Instance.GetTextureStateId(newTextures),
                DrawCallKey.None,
                DrawCallKey.None);

            this.DrawCall = new UserPrimitivesDrawCall<VertexPositionNormalTexture>(
                newDrawCallKey, PrimitiveType.TriangleList, vertices.ToArray(), vertices.Count / 3);
        }

        /// <summary>
        /// Add in rendering pipeline.
        /// </summary>
        /// <param name="renderinPipeline"></param>
        /// <param name="camera"></param>
        public override void AddInRenderingPipeline(RenderingPipeline renderingPipeline, Camera camera)
        {
            renderingPipeline.AddOpaqueGraphicsObject(this.DrawCall, this.World);
        }
    }
}
